package com.alpha.gateway.filter;

import com.alpha.core.http.AlphaHttpContext;
import com.alpha.core.http.HttpConstants;
import com.alpha.core.utils.CollectionUtil;
import com.alpha.core.utils.JsonUtil;
import com.alpha.core.utils.StringUtil;
import com.alpha.gateway.utils.TokenUtil;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 解析 Token 并设置 Http 上下文
 *
 * @author chenruwan
 * @since 2022-01-01
 */
@Component
public class AlphaContextFilter implements WebFilter, Ordered {
    @Override
    @NonNull
    public Mono<Void> filter(ServerWebExchange exchange, @NonNull WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();

        Map<String, Object> clientHeader = new HashMap<>(16);
        clientHeader.put(HttpConstants.HEADER_CLIENT_ID, headers.getFirst(HttpConstants.HEADER_CLIENT_ID));
        clientHeader.put(HttpConstants.HEADER_CLIENT_NAME, headers.getFirst(HttpConstants.HEADER_CLIENT_NAME));

        // Token 放在 Header 中可以解决 XSS 和 XSRF 问题
        String token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StringUtil.isEmpty(token)) {
            AlphaHttpContext.setContext(clientHeader);
            return chain.filter(exchange).doFinally(v -> AlphaHttpContext.clear());
        }

        Map<String, Object> claims = TokenUtil.parseToken(token);
        if (CollectionUtil.isEmpty(claims)) {
            AlphaHttpContext.setContext(clientHeader);
            return chain.filter(exchange).doFinally(v -> AlphaHttpContext.clear());
        }

        claims.putAll(clientHeader);
        AlphaHttpContext.setContext(claims);

        ServerHttpRequest httpRequest = request.mutate().header(HttpConstants.CLAIMS, JsonUtil.toString(claims)).build();
        return chain.filter(exchange.mutate().request(httpRequest).build())
                .doFinally(v -> AlphaHttpContext.clear());
    }

    @Override
    public int getOrder() {
        return -5;
    }
}
